处理异常值

异常值是由于某种原因造成的数据中出现的统计上过大或过小的值,将它们纳入数据分析会影响分析结果。[大谦Excel,dqexcel点com]

9.3.1发现异常值

【问题描述】

判断一个值是否异常有各种不同的方法。下面介绍比较常用的3种方法。第1种方法是使用数据的均值和标准差进行判断,如果数据落在[均值-3×标准差, 均值+3×标准差]范围外,则认为数据是异常值,否则不是。第2种方法是使用分位数进行判断。0.75分位数减去0.25分位数得到数据的内四分极值,如果数据落在[0.25分位数-1.5×内四分极值, 0.75分位数+1.5×内四分极值]范围外,则认为数据是异常值,否则不是。第3种方法用箱形图判断异常值。

【示例9-6】

本例使用的Excel文件的完整路径为“D:/Samples/ch09/03 异常值的处理/异常值.xlsx”。该文件打开后如图9-3所示,是一组测试数据。请找出该数据中的异常值。

Document Image

图9-3 异常值的发现和处理

  • 编写下面的代码:
code.python
import pandas as pd
# 读取Excel文件中第一个工作表前24行数据,引擎为"openpyxl"
df = pd.read_excel('D:/Samples/ch09/03 异常值的处理/异常值.xlsx', sheet_name=0, nrows=24, engine='openpyxl')
# 计算Q1和Q3分位数
Q1 = df['x'].quantile(0.25)
Q3 = df['x'].quantile(0.75)
# 根据四分位距(IQR)检测异常值
IQR = Q3 - Q1
lower_limit = Q1 - 1.5 * IQR
upper_limit = Q3 + 1.5 * IQR
# 查找并输出异常值
outliers = df[(df['x'] < lower_limit) | (df['x'] > upper_limit)]
print("异常值:")
print(outliers)

打开Python IDLE,新建一个脚本文件,将上面生成的代码复制进去,保存。运行脚本,在IDLE Shell窗口输出给定数据中的异常值。

code.python
>>> == RESTART: D:/Samples/1.py =
异常值:
      x
5     3
12  326

可见,本例中用分位数法判定3和326为异常值。

【知识点扩展】

本例用分位数法判断异常值。数据排序后,0.75分位数减去0.25分位数得到数据的内四分极值,如果数据落在[0.25分位数-1.5×内四分极值, 0.75分位数+1.5×内四分极值]范围外,则认为数据是异常值,否则不是。

还可以用数据的均值和标准差进行判断。如果数据落在[均值-3×标准差, 均值+3×标准差]范围外,则认为数据是异常值,否则不是。

  • 下面的代码根据数据的均值和标准差进行判断:
code.python
import pandas as pd
# 读取 Excel 文件,选择第一个工作表,导入前24行数据
df = pd.read_excel('D:/Samples/ch09/03 异常值的处理/异常值.xlsx', sheet_name=0, nrows=24, engine='openpyxl')
# 计算数据的均值和标准差
mean = df['x'].mean()
std_dev = df['x'].std()
# 定义判定异常值的阈值(此处定义为3倍标准差)
threshold = 3 * std_dev
# 利用布尔索引查找异常值,并输出
outliers = df[(df['x'] - mean).abs() > threshold]
print(outliers)

打开Python IDLE,新建一个脚本文件,将上面生成的代码复制进去,保存。运行脚本,在IDLE Shell窗口输出异常值为326。

code.python
>>> == RESTART: D:/Samples/1.py =
      x
12  326
  • 使用箱形图也可以判断异常值。下面的代码根据给定数据绘制箱形图:
code.python
import pandas as pd
import matplotlib.pyplot as plt
# 读取 Excel 文件数据
data = pd.read_excel("D:/Samples/ch09/03 异常值的处理/异常值.xlsx", sheet_name=0, engine="openpyxl", nrows=24)
# 绘制箱形图
plt.boxplot(data["x"], vert=False)
plt.show()

打开Python IDLE,新建一个脚本文件,将上面生成的代码复制进去,保存。运行脚本,得到数据的箱形图如图9-4所示。

Document Image

图9-4 箱形图

箱形图实际上是用图形来表现分位数法。箱形图中间矩形内部的竖线表示数据的中值, 数据的0.75分位数减去0.25分位数得到数据的内四分极值,矩形左右两条边对应于0.25分位数和0.75分位数,两侧的触须对应于0.25分位数-1.5×内四分极值和0.75分位数+1.5×内四分极值。落在触须以外的数据用圆点表示,认为是异常值。

删除异常值

【问题描述】

当一个值被判定为异常值,可以把它当作缺失值进行处理。即可以删除或用指定的值替换。

【示例9-7】

本例使用示例9-6的数据。从给定数据中找到异常值并删除有异常值的行。

  • 编写下面的代码:
code.python
import pandas as pd
# 导入Excel文件数据,读取第一个工作表,引擎为"openpyxl",导入前24行
df = pd.read_excel("D:/Samples/ch09/03 异常值的处理/异常值.xlsx", sheet_name=0, engine="openpyxl", nrows=24)
# 用分位数法查找异常值并删除有异常值的行
# 定义分位数上下限值
q1 = df['x'].quantile(0.25)
q3 = df['x'].quantile(0.75)
iqr = q3 - q1
upper_bound = q3 + 1.5 * iqr
lower_bound = q1 - 1.5 * iqr
# 找到所有大于上限或小于下限的数据
outliers = df[(df['x'] < lower_bound) | (df['x'] > upper_bound)]
# 删除异常值所在的行,并输出修改后的表数据
df.drop(outliers.index, inplace=True)
print(df)

打开Python IDLE,新建一个脚本文件,将上面生成的代码复制进去,保存。运行脚本,在IDLE Shell窗口输出删除异常值后的数据。

code.python
>>> == RESTART: D:/Samples/1.py =
     x
0   48
1   46
2   50
3   38
4   35
6   69
7   34
8   64
9   60
10  58
11  46
13  52
14  38
15  60
……

【知识点扩展】

本例代码使用分位数法查找异常值,首先根据判据逻辑运算表达式得到df中异常值对应的行索引。

code.python
outliers = df[(df['x'] < lower_bound) | (df['x'] > upper_bound)]

然后用DataFrame对象的drop方法删除对应的行。

code.python
# 删除异常值所在的行,并输出修改后的表数据
df.drop(outliers.index, inplace=True)

替换异常值

【问题描述】

除了删除异常值,其他常用的处理异常值的方法为用指定的值替换异常值。

【示例9-8】

本例使用示例9-6的数据。从给定数据中找到异常值并用它上面的数据替换异常值。

  • 编写下面的代码:
code.python
import pandas as pd
# 读取 Excel 文件中第一个工作表的前24行数据,引擎为"openpyxl"
df = pd.read_excel("D:/Samples/ch09/03 异常值的处理/异常值.xlsx", engine="openpyxl", sheet_name=0, nrows=24)
# 计算数据的上下四分位数(Q1和Q3)
q1 = df["x"].quantile(0.25)
q3 = df["x"].quantile(0.75)
# 根据上下四分位数计算异常值阈值
threshold = 1.5 * (q3 - q1)
# 找到所有异常值,并用它上面的值进行替换
for i in range(len(df)):
    if abs(df.loc[i, "x"] - df["x"].median()) > threshold:
        df.loc[i, "x"] = df.loc[i-1, "x"]
# 输出修改后的表数据
print(df)

打开Python IDLE,新建一个脚本文件,将上面生成的代码复制进去,保存。运行脚本,在IDLE Shell窗口输出替换异常值后的数据。

code.python
>>> == RESTART: D:/Samples/1.py =
     x
0   48
1   46
2   50
3   38
4   35
5   35
6   35
7   34
8   64
9   60
10  58
11  46
12  46
13  52
14  38
15  60
……